﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using CB.Logic;
using Swift.Lib;
using System;

namespace CB.Client
{
    /// <summary>
    /// 游戏界面
    /// </summary>
    public abstract class UIGame<TGameData, TBlock, TIcon> : UIContent 
        where TGameData:GameData<TBlock>
        where TBlock:Block 
        where TIcon : BlockIcon<TBlock>
    {
        [SerializeField] private Transform BlocksTrans;
        [SerializeField] protected Transform TargetBlocksTrans;
        [SerializeField] private GameObject Tip;
        [SerializeField] private Button TipBtn;
        [SerializeField] private Button ReturnBtn;

        protected void Awake()
        {
            var bs = BlocksTrans.GetComponentsInChildren<TIcon>();
            int index = 0;
            for (int i = 0; i < 5; i++)
            {
                var l = new List<TIcon>();
                for (int j = 0; j < 5; j++)
                {
                    l.Add(bs[index]);
                    bs[index].Action_ClickBlock = OnClickBlock;
                    index++;
                }
                BlockIcons.Add(l);
            }

            TipBtn.onClick.AddListener(CloseTip);
            ReturnBtn.onClick.AddListener(ReturnUIMain);

            EventManager.Instance.AddListener(EventTypeDefine.BlockMove, StartBlockMove);
            EventManager.Instance.AddListener(EventTypeDefine.GameFinish, ShowTip);
            EventManager.Instance.AddListener(EventTypeDefine.StartNewGame, (db) => SetData());
        }

        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.S))
                OnClickKey(Direction.Up);

            if (Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.W))
                OnClickKey(Direction.Down);

            if (Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.A))
                OnClickKey(Direction.Right);

            if (Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.D))
                OnClickKey(Direction.Left);

        }

        public abstract TGameData GameData { get; protected set; }
        public abstract void SetData();
        protected readonly float DissolveTime = 1.6F;
        public abstract IEnumerator Dissolve(Action act);

        protected List<List<TIcon>> BlockIcons = new List<List<TIcon>>();
        protected List<List<TIcon>> TargetBlockIcons = new List<List<TIcon>>();

        private void StartBlockMove(Dbase db)
        {
            if (!gameObject.activeSelf) return;

            StartCoroutine(DoBlockMove(db));
        }

        private IEnumerator DoBlockMove(Dbase db)
        {
            var f1 = false;
            var f2 = false;

            var x1 = db.QueryInt("X1");
            var y1 = db.QueryInt("Y1");
            var x2 = db.QueryInt("X2");
            var y2 = db.QueryInt("Y2");
            var d = (Direction)db.QueryInt("D");

            var b1 = BlockIcons[y1][x1];
            var b2 = BlockIcons[y2][x2];

            BlockIcons[y1][x1] = b2;
            BlockIcons[y2][x2] = b1;

            b1.DoMove(d, () => f1 = true);
            b2.DoMove((Direction)(Direction.None - d - 1), () => f2 = true);

            yield return new WaitUntil(() => f1 && f2);
            OnAni = false;
            GameManager.Instance.AfterMoveEndCheck();
        }

        protected bool OnAni;

        private void OnClickBlock(Block block)
        {
            if (OnAni)
                return;

            OnAni = GameManager.Instance.TryMoveBlock(block);
        }

        private void OnClickKey(Direction direction)
        {
            if (OnAni)
                return;

            OnAni = GameManager.Instance.DoMove(direction);
        }

        protected virtual void ShowTip(Dbase db)
        {
            if (!gameObject.activeSelf) return;

            Tip.SetActive(true);
        }

        private void CloseTip()
        {
            Tip.SetActive(false);
            StartCoroutine(Dissolve(() => GameManager.Instance.StartNewGame()));
        }

        private void ReturnUIMain()
        {
            this.ShowTransit(() =>
            {
                gameObject.SetActive(false);
                UIManager.Instance.ShowUIContent<UIMain>(UIContentDefine.UIMain);
            });
        }
    }
}
